home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Tool Chest / Development Kits / MPW etc. / Debuggers / SADE / SADE 1.3.3 / SadeStartup < prev    next >
Encoding:
Text File  |  1992-06-12  |  27.9 KB  |  898 lines  |  [TEXT/sade]

  1. ##########################################################################################
  2. #    Symbolic Application Debugging Environment    1.3
  3. #
  4. #    Copyright Apple Computer, Inc. 1987-1992
  5. #    All rights reserved.
  6. #
  7. ##########################################################################################
  8. #
  9. # SADEStartup -- default OnEntry mechanism and support for source level debugging.
  10. #
  11.  
  12. #
  13. # The following variables are used by the OnEntry and source & variable display mechanism.
  14. #
  15. define __SourceDbg__     := 1             # controls source vs. low-level debugging
  16. define __MaxWatchVars__  := 10           # maximum number of watched variables
  17. define __NumWatchVars__  := 0            # current number of watch variables
  18. define __WatchVar__[__MaxWatchVars__]   # names of variables to watch
  19. define __MaxBreakifs__   := 10           # maximum number of conditional breaks
  20. define __BreakifAddr__[__MaxBreakifs__] # conditional break addresses
  21. define __BreakifCond__[__MaxBreakifs__] # conditional break conditions
  22. define __i__
  23. for __i__ := 1 to __MaxBreakifs__ do
  24.     __BreakifAddr__[__i__] := 0
  25. end
  26. undefine __i__
  27.  
  28. FUNC __GetDirectoryFromFullPath__(FullPathName)
  29.     Define DirName := FullPathName
  30.     define i
  31.     for i := Length(DirName) downto 1 do
  32.         if Copy(DirName,i,1) = ':' then
  33.             DirName := Copy(DirName,1,i)
  34.             Return DirName
  35.         END
  36.     END
  37.     Return FullPathName
  38. END
  39.  
  40. FUNC __GetFileFromFullPath__(FullPathName)
  41.     Define FileName := FullPathName
  42.     define i
  43.     for i := Length(FileName) downto 1 do
  44.         if Copy(FileName,i,1) = ':' then
  45.             FileName := Copy(FileName, i+1, Length(FileName))
  46.             Return FileName
  47.         END
  48.     END
  49.     Return FullPathName
  50. END
  51.  
  52. Define SADEDir := __GetDirectoryFromFullPath__(WorksheetWindow)
  53.  
  54. # The "temporary" windows created by Sade are real files.
  55. # These are the register window, the value window, the stack window etc.
  56. # You can select the directory in which they accumulate. If you have a ramdisk,
  57. # override the next line in your SadeUserStartup.
  58. Define __ScratchDir__ := Concat(SADEDir, 'SADE Scratch:')
  59. macro __gValueWindow__ "Concat(__ScratchDir__, 'Value')"
  60. macro __gRegisterWindow__ "Concat(__ScratchDir__, 'Registers')"
  61. macro __gStackWindow__ "Concat(__ScratchDir__, 'Stack Window')"
  62.  
  63. # This sets the size of new windows [top, left, bottom, right]
  64. WindowSize New 0, 0, 200, 400
  65.  
  66. # General error-handling proc.
  67. proc __Fail__(__ErrorString__)
  68.     Alert __ErrorString__
  69.     redirect pop
  70.     Abort
  71. end
  72.  
  73. # This macro is used by scripts below to check if there is a valid target.
  74. macro CheckNullTarget        'if processId = 0 then;alert "No process targeted.";abort;end'
  75.  
  76. # This macro is used to check if the target is running.
  77. macro CheckRunningTarget    'if TargetRunning then;alert "Target is running.";abort;end'
  78. macro CheckNullOrRunningTarget    'CheckNullTarget;CheckRunningTarget'
  79.  
  80. # This macro is used to see if we are at a "LINK A6, $xxxx" instruction
  81. # (local variables are not valid until after the instruction has executed).
  82. macro PCIsAtLinkA6    '^ΔWord(ΔPC)^ = $4E56'    # LINK opword = $4E56
  83.  
  84. # If we haven't executed the LINK instruction, print a warning.
  85. proc CheckValidLocalVars
  86.     CheckRunningTarget
  87.     if PCIsAtLinkA6 then
  88.         printf "Note: Parameters and local variables\naren't valid yet at this statement.\n"
  89.     end
  90. end
  91.  
  92. #
  93. # You may change the default values below to change how source level displays work.
  94. #
  95. define SourceInFront := 1    # controls whether source will be brought up as frontmost window
  96.  
  97. # Set this if you want an alert on hitting a breakpoint.
  98. define Breakalert := 0    # controls breakpoint alert
  99.  
  100. # Set __WantStackWindow__ to 1 if you want a live Stack window which updates every
  101. # time you step.  Since this slows things down, you may prefer to leave it 0 and just
  102. # ask for a snapshot of the stack when you need to.
  103. define __WantStackWindow__ := 0         # controls stack display
  104.  
  105. # Stack display -- the DoStack and DisplayStack procs
  106. proc DoStack
  107.     redirect __gStackWindow__
  108.     if PCIsAtLinkA6 then
  109.         printf "Stack isn't valid yet at this statement.\n"
  110.     else
  111.         stack
  112.     end
  113.     redirect pop
  114.     open __gStackWindow__
  115. end
  116.  
  117. proc DisplayStack
  118.     CheckNullTarget
  119.     if TargetRunning then
  120.         alert "The target is running.  You must halt it to see its stack."
  121.         abort
  122.     end
  123.     DoStack
  124. end
  125.  
  126. proc ToggleWantStackWindow
  127.     if __WantStackWindow__ = 0 then
  128.         __WantStackWindow__ := 1
  129.         Open __gStackWindow__
  130.         addmenu 'Variables' '!Live Stack Window' 'ToggleWantStackWindow'     # '' is control-r (a checkmark)
  131.         DisplayStack
  132.     else
  133.         __WantStackWindow__ := 0
  134.         Save __gStackWindow__
  135.         Close __gStackWindow__
  136.         addmenu 'Variables' 'Live Stack Window' 'ToggleWantStackWindow'
  137.     end
  138. end
  139.  
  140. # Set __WantRegisterWindow__ to 1 if you want a live Registers window which updates every
  141. # time you step.  Since this slows things down, you may prefer to leave it 0 and just
  142. # ask for a snapshot of the registers when you need to.
  143. define __WantRegisterWindow__ := 0         # controls register display
  144.  
  145. #
  146. # Register display -- the Registers and DisplayRegs procs
  147. #
  148. PROC Registers        # This definition must precede the PROC DisplayRegs
  149.     redirect __gRegisterWindow__
  150.     printf ("D0: $%.8X\nD1: $%.8X\nD2: $%.8X\nD3: $%.8X\nD4: $%.8X\nD5: $%.8X\nD6: $%.8X\nD7: $%.8X\n\n",ΔD0,ΔD1,ΔD2,ΔD3,ΔD4,ΔD5,ΔD6,ΔD7)
  151.     printf ("A0: $%.8X\nA1: $%.8X\nA2: $%.8X\nA3: $%.8X\nA4: $%.8X\nA5: $%.8X\nA6: $%.8X\nA7: $%.8X\n\n",ΔA0,ΔA1,ΔA2,ΔA3,ΔA4,ΔA5,ΔA6,ΔA7)
  152.     printf ("PC: $%.8X\n\n",ΔPC)
  153.     printf ("\tXNZVC\n")
  154.     printf ("CCR\t%.5b\n",(ΔCCR & $1F))
  155.     redirect pop
  156. end
  157.  
  158. PROC DisplayRegs # This definition must precede the PROC ToggleWantRegisterWindow
  159.     CheckNullOrRunningTarget
  160.     if TargetRunning then
  161.         alert "The target is running.  You must halt it to see its registers."
  162.         abort
  163.     end
  164.     Registers
  165.     open __gRegisterWindow__
  166. #    SizeWindow To 160,295 __gRegisterWindow__
  167. END
  168.  
  169. proc ToggleWantRegisterWindow
  170.     if __WantRegisterWindow__ = 0 then
  171.         __WantRegisterWindow__ := 1
  172.         addmenu    'Variables' '!Live Register Window' 'ToggleWantRegisterWindow'     # '' is control-r (a checkmark)
  173.         DisplayRegs
  174.         open __gRegisterWindow__
  175.     else
  176.         __WantRegisterWindow__ := 0
  177.         save __gRegisterWindow__
  178.         close __gRegisterWindow__
  179.         addmenu    'Variables' 'Live Register Window' 'ToggleWantRegisterWindow'
  180.     end
  181. end
  182.  
  183. #
  184. # You can set the Safety variable to 1 if you want SADE to be more careful
  185. # when stepping and breaking.  The default setting slightly increases the
  186. # possibility of SADE crashing because of a memory stomper in user code,
  187. # but makes stepping and breaking ten times faster.
  188. #
  189. Safety := 0
  190.  
  191. #
  192. # By default, BreakifNoSource is false.  This allows SADE to step
  193. # through routines like LMODT and UDIVT.  It also lets SADE step
  194. # through Object Pascal and MacApp method dispatch code.  However,
  195. # if you have enabled symbolics for only a small portion of your
  196. # code and do a step into, it will appear that SADE has hung when
  197. # it is really single stepping through zillions of instructions.
  198. # The default setting of 0 supports MacApp and avoids mystery
  199. # breaks in LMODT.  See the "SADE New User WorkSheet" for details.
  200. BreakifNoSource := 0
  201.  
  202. proc ToggleBreakifNoSource
  203.     if BreakifNoSource = 0 then
  204.         BreakifNoSource := 1
  205.         addmenu 'SourceCmds' '!Break if No Source' 'ToggleBreakifNoSource'     # '' is control-r (a checkmark)
  206.     else
  207.         BreakifNoSource := 0
  208.         addmenu 'SourceCmds' 'Break if No Source' 'ToggleBreakifNoSource'
  209.     end
  210. end
  211.  
  212. #
  213. # By default, __StopBeforeStatic__ is 0.  This makes SADE step to
  214. # main.(0) when an application is launched.  If you set it to 1, SADE
  215. # will give you control before any code in the app is run.  You can then
  216. # place breakpoints at your static constructors before you proceed.
  217. #
  218. define __StopBeforeStatic__ := 0
  219.  
  220. proc ToggleStopBeforeStatic
  221.     if __StopBeforeStatic__ = 0 then
  222.         __StopBeforeStatic__ := 1
  223.         addmenu 'File' '!Stop Before Constructor' 'ToggleStopBeforeStatic'
  224.     else
  225.         __StopBeforeStatic__ := 0
  226.         addmenu 'File' 'Stop Before Constructor' 'ToggleStopBeforeStatic'     # '' is control-r (a checkmark)
  227.     end
  228. end
  229.  
  230. proc ToggleSourceDbg
  231.     if __SourceDbg__ = 0 then
  232.         __SourceDbg__ := 1
  233.         deletemenu 'SourceCmds' '!Asm [vs. Source] Debugging'     # '' is control-r (a checkmark)
  234.         addmenu 'SourceCmds' '!Source [vs. Asm] Debugging' 'ToggleSourceDbg'     # '' is control-r (a checkmark)
  235.     else
  236.         __SourceDbg__ := 0
  237.         deletemenu 'SourceCmds' '!Source [vs. Asm] Debugging'     # '' is control-r (a checkmark)
  238.         addmenu 'SourceCmds' '!Asm [vs. Source] Debugging' 'ToggleSourceDbg'     # '' is control-r (a checkmark)
  239.     end
  240. end
  241.  
  242. # Return true if the 1st character of __theStr__ is in [A-Z,a-z,_]
  243. func IsAlpha(__theStr__)
  244.     define __theChar__ := copy(__theStr__, 1, 1)
  245.     if (__theChar__ >= 'a') and (__theChar__ <= 'z') then
  246.         return 1
  247.     end
  248.     if (__theChar__ >= 'A') and (__theChar__ <= 'Z') then
  249.         return 1
  250.     end
  251.     if (__theChar__ = '_') then
  252.         return 1
  253.     end
  254.     return 0
  255. end
  256.  
  257. # Add a backquote to the selected name to evaluate it as a program variable.
  258. func QualifiedVariableName(__VarName__)
  259.     if copy(__VarName__, 1, 1) = '`' then
  260.         return __VarName__
  261.     end
  262.     if IsAlpha(__VarName__)
  263.         return Concat('`', __VarName__)
  264.     end
  265.     return __VarName__
  266. end
  267.  
  268. FUNC CheckedEval(__Expression__, __ErrorString__)
  269.     Define __EvaledExpr__
  270.     __EvaledExpr__ := Eval(__Expression__,'???')
  271.     IF TypeOf(__EvaledExpr__) = 'PString' then
  272.         IF __EvaledExpr__ = '???' THEN
  273.             __Fail__(Concat(__ErrorString__, __Expression__))
  274.         ELSEIF Copy(__EvaledExpr__, 1, 21) = '### Eval syntax error' then
  275.             __Fail__(Concat('Expression syntax error: ', __Expression__))
  276.         END
  277.     END
  278.     RETURN __EvaledExpr__
  279. END
  280.  
  281. # Print a variable's name and value, with linebreaks as necessary.
  282. proc PrettyPrintValue(__TheVarName__)
  283. #    __TheVarName__ := QualifiedVariableName(__TheVarName__)
  284.     define __EvaledVar__ := CheckedEval(__TheVarName__, 'Undefined/Out of scope: ')
  285.     if SizeOf(__EvaledVar__) > 4 then
  286.         printf "%s =\n%t\n", __TheVarName__, __EvaledVar__
  287.     else
  288.         printf "%s = %t\n", __TheVarName__, __EvaledVar__
  289.     end
  290. end
  291.  
  292. # Print a variable's name and its value in hex, with linebreaks as necessary.
  293. proc PrettyPrintValueInHex(__TheVarName__)
  294. #    __TheVarName__ := QualifiedVariableName(__TheVarName__)
  295.     define __EvaledVar__ := CheckedEval(__TheVarName__, 'Undefined/Out of scope: ')
  296.     if TypeOf(__EvaledVar__) = 'PString' then
  297.         printf "Printing strings as hex values does not work well.\n"
  298.     end
  299.     if SizeOf(__EvaledVar__) > 4 then
  300.         printf "%s = Can not print non-integral objects as hex values.\n",__TheVarName__
  301.         return
  302.     else
  303.         printf "%s = $%X\n", __TheVarName__, __EvaledVar__
  304.     end
  305. end
  306.  
  307. proc PrettyPrintValueNoAlert(__TheVarName__)
  308.     __TheVarName__ := QualifiedVariableName(__TheVarName__)
  309.     define __EvaledVar__ := Eval(__TheVarName__, '???')
  310.     IF TypeOf(__EvaledVar__) = 'PString' THEN
  311.         IF __EvaledVar__ = '???' THEN
  312.             Printf "%s = Undefined/Out of scope\n", __TheVarName__
  313.             return
  314.         ELSEIF Copy(__EvaledVar__, 1, 21) = '### Eval syntax error' then
  315.             Printf "%s = Expression syntax error\n", __TheVarName__
  316.             return
  317.         END
  318.     END
  319.     if SizeOf(__EvaledVar__) > 4 then
  320.         printf "%s =\n%t\n", __TheVarName__, __EvaledVar__
  321.     else
  322.         printf "%s = %t\n", __TheVarName__, __EvaledVar__
  323.     end
  324. end
  325.  
  326. # Display the watch variables.
  327. proc DisplayWatchVars
  328.     define __i__
  329.     redirect Concat(__ScratchDir__, "Variable Watch")
  330.     CheckValidLocalVars
  331.     for __i__ := 1 to __NumWatchVars__ do
  332.         PrettyPrintValueNoAlert(__WatchVar__[__i__])
  333.     end
  334.     redirect pop
  335.     open behind Concat(__ScratchDir__, "Variable Watch")
  336. end
  337.  
  338. #••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
  339. #
  340. # Entry handling -- the StandardEntry proc
  341. #
  342. macro kSEProcessLoaded        '65'
  343. macro kSETrace                '51'
  344. macro kSEAddressBreak        '58'
  345. macro kSESADEKeyInterrupt    '55'
  346. macro kSEProcessHalted        '8194'
  347.  
  348. func GetErrorString()
  349.     define __errCause__ := ''
  350.     if Exception = kSETrace then
  351.         __errCause__ := "Instruction trace"
  352.     elseif Exception = kSEAddressBreak then
  353.         __errCause__ := "Address Break encountered"
  354.     elseif Exception = 50 then
  355.         __errCause__ := "Trap Break encountered"
  356.     elseif (Exception = kSESADEKeyInterrupt) | (Exception = 13) then 
  357.         __errCause__ := "Program interrupted"
  358.     elseif (Exception = kSEProcessHalted) then 
  359.         __errCause__ := "Process Halted"
  360.     elseif Exception = 1 then
  361.         __errCause__ := "Bus Error"
  362.     elseif Exception = 2 then
  363.         __errCause__ := "Address Error"
  364.     elseif Exception = 3 then
  365.         __errCause__ := "Illegal instruction encountered"
  366.     elseif Exception = 4 then
  367.         __errCause__ := "Divide by zero encountered"
  368.     elseif Exception = 5 then
  369.         __errCause__ := "CHK exception (array index out of range) encountered"
  370.     elseif Exception = 6 then
  371.         __errCause__ := "TRAPV or TRAPcc instruction encountered"
  372.     elseif Exception = 7 then
  373.         __errCause__ := "Privilege Violation"
  374.     elseif Exception = 63 then
  375.         __errCause__ := "Internal non-fatal error!  You may be able to proceed..."
  376.     elseif Exception = 64 then
  377.         __errCause__ := "Internal fatal error!  Please kill the target process!"
  378.     elseif Exception = kSEProcessLoaded then
  379.         __errCause__ := "Initial program break encountered"
  380.     elseif Exception = -490 then
  381.         __errCause__ := "User Break encountered"
  382.     elseif Exception = -491 then
  383.         __errCause__ := Concat ("∂"", ^PString(ΔSP^)^, "∂"")
  384.         ΔSP := ΔSP+4;
  385.     elseif Exception = -492 then
  386.         __errCause__ := Concat ("Execute message not implemented ∂"", ^PString(ΔSP^)^, "∂"")    # currently no way to execute this from SADE!
  387.         ΔSP := ΔSP+4;
  388.     elseif Exception = -490 then
  389.         __errCause__ := "User Break encountered"
  390.     else
  391.         __errCause__ := Concat('Error number ', Exception)
  392.     end
  393.     return __errCause__
  394. end
  395.  
  396. PROC __BreakBehavior__(__errCause__)
  397.     Alert Concat(__errCause__, ' at ', where(ΔPC))
  398. #    Beep
  399. END
  400.  
  401. PROC __UserEntryBehavior__
  402. END
  403.  
  404. proc StandardEntry
  405.     __UserEntryBehavior__
  406.  
  407.     # if we are at the startup code for a C program, move ahead to main.(0)
  408.     if Exception = kSEProcessLoaded then
  409.         if __StopBeforeStatic__ = 0 then
  410.             if Eval('main.(0)', '????') <> '????' then
  411.                 go til main.(0)
  412.                 stop
  413.             end
  414.         end
  415.     end
  416.  
  417.     define __errCause__
  418.     if __SourceDbg__ then
  419.         if addrToSource(ΔPC, SourceInFront) and (Exception > 0) then
  420.             if Exception <> kSETrace then
  421.                 __errCause__ := GetErrorString()
  422.                 if Breakalert then 
  423.                     __BreakBehavior__(__errCause__)
  424.                 elseif (Exception <> kSEprocessLoaded) and (Exception <> kSEAddressBreak) and (Exception <> kSESADEKeyInterrupt) then
  425.                     alert Concat(__errCause__, ' at ', where(ΔPC))
  426.                 end
  427.             end
  428.         else
  429.             Open WorksheetWindow
  430.             __errCause__ := GetErrorString()
  431.             printf "%s at ", __errCause__
  432.             disasm ΔPC 1
  433.         end
  434.     else        # Assembly mode
  435.         Open WorksheetWindow
  436.         if Exception <> kSETrace then
  437.             __errCause__ := GetErrorString()
  438.             printf "%s at ", __errCause__
  439.         end
  440.         disasm ΔPC 1
  441.     end
  442.     
  443.     if __NumWatchVars__ > 0 then
  444.         DisplayWatchVars
  445.     end
  446.  
  447.     if __WantStackWindow__ then
  448.         DoStack
  449.     end
  450.  
  451.     if __WantRegisterWindow__ then
  452.         Registers
  453.     end
  454. end
  455.  
  456. OnEntry StandardEntry
  457.  
  458.  
  459. #
  460. # Macsbug equivalent command names for SADE
  461. # if you want these, remove the leading comments.
  462. # NOTE that these macros will be found before any program variables
  463. # of the same name!
  464. #
  465. # macro    g         "go"
  466. # macro    il        "disasm"
  467. # macro    ip        "disasm ΔPC-20 40"
  468. # macro    br        "break"
  469. # macro    ht        "heap totals"
  470. # macro    hd        "heap display"
  471. # macro    atba    "break all traps from applzone..applzone^"
  472. # macro    mc        "macro"
  473. # macro    id        "disasm"
  474. # macro    sc        "stack"
  475. # macro td        "registers"
  476.  
  477. #
  478. # Source Breakpoints
  479. #
  480. proc SetSourceBreak
  481.     CheckNullTarget
  482.     define __sourceBreak__ := sourceToAddr(activeWindow, 1)
  483.     if typeof(__sourceBreak__) = 'PString' then
  484.         alert Concat('Cannot determine break address: ', __sourceBreak__)
  485.     else
  486.         break __sourceBreak__
  487.         if not addrToSource(__sourceBreak__, 1) then    # verify statement selection
  488.             alert 'Able to set but not display breakpoint; SourcePath may not be set'
  489.         end
  490.     end
  491. end
  492.  
  493. proc ProcessBreakIf        # used by SetSourceBreakIf below
  494.     define __i__
  495.     define __addr__
  496.     for __i__ := 1 to __MaxBreakifs__ do
  497.         __addr__ := __BreakifAddr__[__i__]
  498.         if __addr__ = ΔPC then
  499.             if eval(__BreakifCond__[__i__]) then
  500.                 stop
  501.             end
  502.         end
  503.     end
  504. end
  505.  
  506. proc SetSourceBreakIf
  507.     CheckNullTarget
  508.     define __i__, __j__, __condition__, __EvaledCondition__
  509.     define __sourceBreak__ := sourceToAddr(activeWindow, 1)
  510.     if typeof(__sourceBreak__) = 'PString' then
  511.         alert Concat('Cannot determine break address: ', __sourceBreak__)
  512.         abort
  513.     end
  514.     if (__condition__ := request('Condition to break on?')) = '_CANCEL_' then
  515.         abort
  516.     end
  517.     if __condition__ = '' then
  518.         alert 'No condition was specified; break not set'
  519.         abort
  520.     end
  521.     # check for valid condition
  522.     __EvaledCondition__ := eval(__condition__, '???')
  523.     if typeof(__EvaledCondition__) = 'PString' then
  524.         if __EvaledCondition__ = '???' then
  525.             if not confirm('Variable not defined in current scope.  Still set conditional break?') then
  526.                 abort
  527.             end
  528.         elseif copy(__EvaledCondition__, 1, 21) = '### Eval syntax error' then
  529.             alert Concat('Cannot set conditional break.  Expression syntax error: ', __condition__)
  530.             abort
  531.         end
  532.     end
  533.     # try to add to conditional break table
  534.     for __i__ := 1 to __MaxBreakifs__ + 1 do
  535.         if __i__ = (__MaxBreakifs__ + 1) then
  536.             if not confirm('Conditional break table full; remove the oldest conditional break?') then
  537.                 abort
  538.             end
  539.             unbreak __BreakifAddr__[1]                # remove the first installed
  540.             for __j__ := 2 to __MaxBreakifs__ do    # shift the others over
  541.                 __BreakifAddr__[__j__ - 1] := __BreakifAddr__[__j__]
  542.                 __BreakifCond__[__j__ - 1] := __BreakifCond__[__j__]
  543.             end                                        # remember the new one
  544.             __BreakifAddr__[__MaxBreakifs__] := __sourceBreak__
  545.             __BreakifCond__[__MaxBreakifs__] := __condition__
  546.             leave
  547.         elseif (__BreakifAddr__[__i__] = 0) | (__sourceBreak__ = __BreakifAddr__[__i__]) then
  548.             __BreakifAddr__[__i__] := __sourceBreak__
  549.             __BreakifCond__[__i__] := __condition__
  550.             leave
  551.         end
  552.     end
  553.     break __sourceBreak__ processBreakIf
  554.     if not addrToSource(__sourceBreak__, 1) then    # verify statement selection
  555.         alert 'Able to set but not display breakpoint; SourcePath may not be set'
  556.     end
  557. end
  558.  
  559. PROC __ClearBreakTable__
  560.     define __i__
  561.     for __i__ := 1 to __MaxBreakifs__ do
  562.         __BreakifAddr__[__i__] := 0
  563.     end
  564. END
  565.  
  566. PROC __UnbreakAll__
  567.     CheckNullTarget
  568.     Unbreak All
  569.     __ClearBreakTable__
  570. END
  571.  
  572. proc UnSetSourceBreak
  573.     CheckNullTarget
  574.     define __i__
  575.     define __sourceBreak__ := sourceToAddr(activeWindow, 1)
  576.     if typeof(__sourceBreak__) = 'PString' then
  577.         alert Concat('Cannot determine break address: ', __sourceBreak__)
  578.     else
  579.         unbreak __sourceBreak__
  580.         for __i__ := 1 to __MaxBreakifs__ do                # remove from Breakif table if present
  581.             if __sourceBreak__ = __BreakifAddr__[__i__] then
  582.                 __BreakifAddr__[__i__] := 0
  583.                 leave
  584.             end
  585.         end
  586.         if addrToSource(__sourceBreak__, 1) then; end    # verify statement selection
  587.     end
  588. end
  589.  
  590. proc StepMenu
  591.     CheckNullOrRunningTarget
  592.     if __SourceDbg__ = 0 then
  593.         step asm
  594.     else
  595.         step
  596.     end
  597. end
  598.  
  599. proc StepIntoMenu
  600.     CheckNullOrRunningTarget
  601.     if __SourceDbg__ = 0 then
  602.         step asm into
  603.     else
  604.         step into
  605.     end
  606. end
  607.  
  608. proc StepOut
  609.     CheckNullOrRunningTarget
  610.     if PCIsAtLinkA6    then    # if we are looking at a LINK instruction, A6 has not been
  611.         go til (ΔA7)^        #   set up but ΔA7 probably contains the right value
  612.     else                    # if a LINK has already taken place,
  613.         go til (ΔA6+4)^        #   the return address is at ΔA6+4
  614.     end
  615. end
  616.  
  617. proc GoTil
  618.     CheckNullOrRunningTarget
  619.     define __sourceBreak__ := sourceToAddr(activeWindow, 1)
  620.     if typeof(__sourceBreak__) = 'PString' then
  621.         alert Concat('Cannot determine break address: ', __sourceBreak__)
  622.     else
  623.         go til __sourceBreak__
  624.     end
  625. end
  626.  
  627. proc InWhatStatement
  628.     CheckNullOrRunningTarget
  629.     if NOT addrToSource(ΔPC, SourceInFront) then
  630.         alert "Cannot find source for PC."
  631.     end
  632. end
  633.  
  634. proc ShowWhere
  635.     define __loc__
  636.     CheckNullTarget
  637.     __loc__ := sourceToAddr(ActiveWindow, 1)
  638.     if typeof(__loc__) = 'PString' then
  639.         alert Concat('Cannot determine address from source: ', __loc__)
  640.     else
  641.         alert Concat('At ', where(__loc__))
  642.     end
  643. end
  644.  
  645. proc __CheckNullSelection__(__theSelection__)
  646.     if Length(__theSelection__) = 0 then
  647.         __Fail__("Selection is zero-length.")
  648.     end
  649. end
  650.  
  651. proc ShowSource(__theSelection__)
  652.     CheckNullTarget
  653.     __CheckNullSelection__(__theSelection__)
  654.     define __theFunc__ := Eval(__theSelection__, '???')
  655.     if typeof(__theFunc__) = 'PString' then
  656.         if __theFunc__ = '???' then
  657.             alert Concat('"', __theSelection__, '" is not a function or procedure name which is known at this point.')
  658.         else
  659.             alert Concat('"', __theSelection__, '" is not a function or procedure name.')
  660.         end
  661.         abort
  662.     end
  663.     if typeof(__theFunc__) <> 'CodeModule' then
  664.         alert Concat('"', __theSelection__, '" is not a function or procedure.')
  665.     elseif not addrToSource(__theFunc__, 1) then
  666.         alert Concat('The source for "', __theSelection__, '" could not be found.')
  667.     end
  668. end
  669.  
  670. proc ShowValue(__theSelection__)
  671.     CheckNullOrRunningTarget
  672.     __CheckNullSelection__(__theSelection__)
  673.     Open __gValueWindow__
  674.     redirect append __gValueWindow__
  675.     CheckValidLocalVars
  676.     PrettyPrintValue(__theSelection__)
  677.     redirect pop
  678. end
  679.     
  680. proc ShowValueInHex(__theSelection__)
  681.     CheckNullOrRunningTarget
  682.     __CheckNullSelection__(__theSelection__)
  683.     redirect append __gValueWindow__
  684.     CheckValidLocalVars
  685.     PrettyPrintValueInHex(__theSelection__)
  686.     redirect pop
  687.     Open __gValueWindow__
  688. end
  689.  
  690. proc __CheckPointer__(__thePointer__)
  691.     define __ErrorMessage__
  692.     define __EvaledPointer__ := CheckedEval(__thePointer__, 'Undefined/Out of scope: ')
  693.     define __TypeOfPointer__ := Typeof(__EvaledPointer__)
  694.     IF SizeOf(__EvaledPointer__) <> 4 THEN
  695.         # Not a pointer object
  696.         __Fail__(Concat(__thePointer__, " is not a pointer."))
  697.     END
  698.     IF __TypeOfPointer__ = '^Void' THEN
  699.         __Fail__(Concat('Can not dereference (void*) ', __thePointer__))
  700.     END
  701.     if __EvaledPointer__ = 0 then
  702.         __ErrorMessage__ := Concat('Cannot dereference NULL ', __thePointer__)
  703.         __Fail__(__ErrorMessage__)
  704.     end    
  705. end
  706.  
  707. proc ShowDereferencedValue(__theSelection__)
  708.     CheckNullOrRunningTarget
  709.     __CheckNullSelection__(__theSelection__)
  710.     __theSelection__ := QualifiedVariableName(__theSelection__)
  711.     __CheckPointer__(__theSelection__)
  712.     ShowValue(Concat(__theSelection__, '^'))
  713. end
  714.  
  715. proc ShowDereferencedValueInHex(__theSelection__)
  716.     CheckNullOrRunningTarget
  717.     __CheckNullSelection__(__theSelection__)
  718.     __theSelection__ := QualifiedVariableName(__theSelection__)
  719.     __CheckPointer__(__theSelection__)
  720.     ShowValueInHex(Concat(__theSelection__, '^'))
  721. end
  722.  
  723. proc AddWatchVar(__theSelection__)
  724.     CheckNullOrRunningTarget
  725.     __CheckNullSelection__(__theSelection__)
  726.     define __EvaluedExpr__
  727.     if __NumWatchVars__ > (__MaxWatchVars__ - 1) then
  728.         alert "Cannot add more watch variables"
  729.     else
  730.         __theSelection__ := QualifiedVariableName(__theSelection__)
  731.         __EvaluedExpr__ := Eval(__theSelection__, '???')
  732.         if typeof(__EvaluedExpr__) = 'PString' then
  733.             if copy(__EvaluedExpr__, 1, 21) = '### Eval syntax error' then
  734.                 alert Concat('Cannot add watch variable.  Expression syntax error: ', __theSelection__)
  735.                 return
  736.             elseif __EvaluedExpr__ = '???' then
  737.                 if not confirm(Concat(__theSelection__, ' not defined at this time.  Still add as watch variable?')) then
  738.                     return
  739.                 end
  740.             end
  741.         end
  742.         __NumWatchVars__ := __NumWatchVars__ + 1
  743.         __WatchVar__[__NumWatchVars__] := __theSelection__
  744.         # Now refresh the display window
  745.         DisplayWatchVars
  746.     end
  747. end
  748.  
  749.  
  750. proc DeleteWatchVar(__theSelection__)
  751.     CheckNullTarget
  752.     __CheckNullSelection__(__theSelection__)
  753.     define __i__, __found__ := 0
  754.     __theSelection__ := QualifiedVariableName(__theSelection__)
  755.     for __i__ := 1 to __NumWatchVars__ do
  756.         if __found__ then
  757.             __WatchVar__[__i__-1] := __WatchVar__[__i__]
  758.         elseif __theSelection__ = __WatchVar__[__i__] then
  759.             __found__ := 1
  760.         end
  761.     end
  762.     if __found__ then
  763.         __WatchVar__[__NumWatchVars__] := 0
  764.         __NumWatchVars__ := __NumWatchVars__ - 1
  765.         # Now refresh the display window
  766.         DisplayWatchVars
  767.     else
  768.         alert Concat('Cannot find watch variable "', __theSelection__, '" to delete')
  769.     end
  770. end
  771.  
  772. proc DeleteAllWatchVars
  773.     __NumWatchVars__ := 0
  774.     Save Concat(__ScratchDir__, "Variable Watch")
  775.     Close Concat(__ScratchDir__, "Variable Watch")
  776. end
  777.  
  778.  
  779. proc SADEHelp(__theSelection__)
  780.     Define __HelpWindowName__ := Concat(__ScratchDir__, "SADE_Info")
  781.     Redirect __HelpWindowName__
  782.     printf "#   Select a word and then choose the SADE Help menu item.\n"
  783.     printf "#       try:  BuiltIns   Commands   Expressions  Patterns\n"
  784.     printf "#          :  Shortcuts  Variables  Basetypes    <commandName>\n\n"
  785.     #
  786.     if __theSelection__ = '' then
  787.         __theSelection__ := "Commands"
  788.     end
  789.     help expr(__theSelection__)
  790.     redirect pop
  791.     open __HelpWindowName__
  792.     define __dummy__
  793.     __dummy__ := selection(__HelpWindowName__, 0, 0)
  794. end
  795.  
  796.  
  797. #
  798. #
  799. # Killing or untargeting the target
  800. # Killing a target means to terminate it.  Untargeting it, however, simply means for
  801. # SADE to stop treating it as a target.  The semantics of untargeting are as follows:
  802. # if the target is running, it is left running.  If it is suspended at a breakpoint,
  803. # it is restarted.  If it is suspended due to a "hard" exception (e.g. a bus error),
  804. # it is killed.
  805. # Care is required in killing MPW tools.  Since in debugging a tool SADE's target is
  806. # actually the MPW shell, the kill command will kill the shell as well as the tool.
  807. # To avoid this, the KillTool proc below will kill a suspended tool without killing
  808. # the shell.  (KillTool won't kill a running tool.)  The KillTarget proc checks the
  809. # type of the target and executes either Kill or KillTool as appropriate.
  810. #
  811.  
  812. proc UnTarget
  813.     Target ''
  814.     __ClearBreakTable__
  815. end
  816.  
  817. proc KillTool
  818.     ΔPC := @µSYSRECOVER                # set the pc to the shell's error recovery routine
  819.     go
  820. end
  821.  
  822. proc KillTarget
  823.     if TargetIsMPWTool then
  824.         KillTool
  825.     else
  826.         kill
  827.     end
  828.     __ClearBreakTable__
  829.     __NumWatchVars__ := 0
  830. end
  831.  
  832.  
  833. #
  834. #
  835. # SADE menu initialization
  836. # Sets up SourceCmds and Variables menus, and adds Kill, Quit, and Help items
  837. # to the File menu.
  838. #
  839. #
  840.  
  841. addmenu 'File' 'Stop Before Constructor'                'ToggleStopBeforeStatic'
  842. addMenu 'File' 'Kill'                                    'KillTarget'
  843. addMenu 'File' '(-'                                        ''
  844.  
  845. # The default quit menu saves all dirty files before quitting.
  846. # Use the commented-out form if you'd rather be prompted than save automatically.
  847.  
  848. #addMenu 'File' 'Quit /Q'                                'quit'
  849. addMenu 'File' 'Quit /Q'                                'Save All;Quit'
  850.  
  851. addMenu 'Find' '(-'                                        ''
  852. addMenu 'Find' 'SADE Help/1'                             'SADEHelp(selection(ActiveWindow))'
  853.  
  854. addmenu 'SourceCmds' 'Break /B'                           'SetSourceBreak'
  855. addmenu 'SourceCmds' 'Break if…/∫'                        'SetSourceBreakIf'
  856. addmenu 'SourceCmds' 'Unbreak /U'                         'UnSetSourceBreak'
  857. addmenu 'SourceCmds' 'Unbreak All'                        '__UnbreakAll__'
  858. addmenu 'SourceCmds' '(-'                 ''
  859. addmenu 'SourceCmds' 'Step /L'                            'StepMenu'
  860. addmenu 'SourceCmds' 'Step Into /¬'                       'StepIntoMenu'        # '¬' is Opt-l
  861. addmenu 'SourceCmds' 'Step Out'                           'StepOut'
  862. addmenu 'SourceCmds' '(-'                 ''
  863. addmenu 'SourceCmds' 'Go /P'              'go'
  864. addmenu 'SourceCmds' 'Go Til /π'                         'GoTil'
  865. addmenu 'SourceCmds' '(-'                 ''
  866. addMenu 'SourceCmds' 'In What Statement? /I'            'InWhatStatement'
  867. addMenu 'SourceCmds' 'Statement Selected Is?'            'ShowWhere'
  868. addMenu 'SourceCmds' 'Show Selected Routine'            'ShowSource(selection(ActiveWindow))'
  869. addmenu 'SourceCmds' '(-'                 ''
  870. addmenu 'SourceCmds' 'Break if No Source'                'ToggleBreakifNoSource'
  871. addmenu 'SourceCmds' '!Source [vs. Asm] Debugging'        'ToggleSourceDbg'     # '' is control-r (a checkmark)
  872.  
  873. addmenu 'Variables'  'Show Value /√'                    'ShowValue(selection(ActiveWindow))'    # '√' is Opt-v
  874. addmenu 'Variables'  'Show Dereferenced Value /◊'        'ShowDereferencedValue(selection(ActiveWindow))'    # '◊' is Opt-shift-v
  875. addmenu 'Variables'  'Show Value in Hex'                'ShowValueInHex(selection(ActiveWindow))'
  876. addmenu 'Variables'  'Show Dereferenced Value in Hex'    'ShowDereferencedValueInHex(selection(ActiveWindow))'
  877. addmenu 'Variables'  '(-'                                ''
  878. addmenu 'Variables'  'Add Watch Variable'                'AddWatchVar(selection(ActiveWindow))'
  879. addmenu 'Variables'  'Delete Watch Variable'            'DeleteWatchVar(selection(ActiveWindow))'
  880. addmenu 'Variables'  'Delete All Watch Variables'        'DeleteAllWatchVars'
  881. addmenu 'Variables'  '(-'                                 ''
  882. addmenu 'Variables'  'Show Registers'                    'DisplayRegs'
  883. addmenu 'Variables'  'Live Register Window'                'ToggleWantRegisterWindow'
  884. addmenu 'Variables'  '(-'                 ''
  885. addmenu 'Variables'  'Show Stack'                        'DisplayStack'
  886. addmenu 'Variables'  'Live Stack Window'                'ToggleWantStackWindow'
  887.  
  888. #
  889. # Execute SADEUserStartup, where you can add to and modify the stuff supplied here.
  890. #
  891. # NOTE: The order in which SADE executes startup files is:  1. SadeStartup,
  892. # 2. SadeUserStartup, 3... Any SADE text file beginning with 'SadeUserStartup•',
  893. # in alphabetical order.  So if you want to override behavior defined in ANY other
  894. # script, be sure to define it in a script named something like 'SadeUserStartup•zzz'
  895. # which will be executed last.
  896. #
  897. execute ':SadeUserStartup'
  898.